#include "miniutil/thread.h"
#include "miniutil/threadservice.h"
#include "miniutil/log.h"
#ifdef WIN32
#include "miniutil/exceptioncapture_w32.h"
#endif

namespace miniutil { namespace frame {
	
ThreadService::ThreadService(int sleepms)
{
	msleeptime = sleepms;
	mbrunning = false;
#ifdef WIN32
	workerhandle = NULL;
#else
	exitflg = 0;
#endif
	mstarttm = 0x00;
	mstoptm = 0x00;
}

int ThreadService::Start()
{
	int ret;
#ifdef WIN32
    ExceptionCapture::GetInstance()->AddExceptionHandler("dumpfile");
#endif
	miniutil::auto_lock kk(&mservice_mtx);
	if(mbrunning)
		return -1;
	ret = BeforeStart();
	if(ret != 0)
		return -1;
	exitflg = 0;
	mbrunning = true;
	mstarttm = time(NULL);
#ifdef WIN32
	{
		DWORD dwThreadID;
		workerhandle = CreateThread( (LPSECURITY_ATTRIBUTES) NULL, /*security attribute*/
					0,/* size of thread stack, same as main thread by default*/
					(LPTHREAD_START_ROUTINE)WorkingThread, /* thread entry function */
					this, 0, &dwThreadID);
		if(workerhandle == NULL)
		{
			M_DEBUG("ThreadService:Create Thread Error:%d\n", GetLastError());
		}
	}
#else
#ifndef EAGAIN
#define EAGAIN 11
#endif

#ifndef EINVAL
#define EINVAL 22
#endif

	{
		pthread_t tid;
		int ret = pthread_create(&tid,NULL,WorkingThread,this);
		if(ret == EAGAIN)
		{
			M_DEBUG("pthread_create EAGAIN!\n");
		}
		else if(ret == EINVAL)
		{
			M_DEBUG("pthread_create EINVAL!\n");
		}
		else if(ret != 0)
		{
			M_DEBUG("pthread_create %d!\n", ret);
		}
		else
		{
			pthread_detach(tid);
		}
	}
#endif
	return 0;
}

int ThreadService::Stop()
{
	int ret;
	miniutil::auto_lock kk(&mservice_mtx);
	if(!mbrunning)
		return -1;

	//ret = BeforeStop();
	//if(ret == -1)
	//	return -1;
#ifdef WIN32
	if(workerhandle != NULL)
	{
		exitflg = 1;
		DWORD exitcode;
		while( true)
		{
			ret = GetExitCodeThread(workerhandle, &exitcode);
			if(ret != 0 && exitcode == STILL_ACTIVE)
				Sleep(100);
			else
				break;
		}
		workerhandle = NULL;
	}
#else
	exitflg = 1;

	while(exitflg != 2)
        miniutil::thread::sleep(100);

#endif
	exitflg = 0;
	mbrunning = false;
	AfterStop();
	return 0;
}

int ThreadService::InnerRun()
{
	int ret;
	ret = AfterStart();
	if(ret != -1)
	{
		while(true)
		{
			if(exitflg == 1)
				break;
			ret = WorkingTask();
			if(ret == -1)
				break;
			miniutil::thread::sleep(msleeptime);
		}
	}
	
	BeforeStop();
    return 0;
}

int ThreadService::InnerRunException()
{
#ifdef WIN32
    __try
    {
#endif
	int ret;
	ret = AfterStart();
	if(ret != -1)
	{
		while(true)
		{
			if(exitflg == 1)
				break;
			ret = WorkingTask();
			if(ret == -1)
				break;
			miniutil::thread::sleep(msleeptime);
		}
	}
	
	BeforeStop();
#ifdef WIN32
    }
	__except((*ExceptionCapture::GetInstance())(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER)
	{
        M_DEBUG("\r\n\r\n!!!!!!!!!!!!!!!!!!!!!!!\r\n\r\nThreadService meet a fatal exception!\r\n");
	}
    
#endif
    return 0;
}


#ifdef WIN32
int ThreadService::WorkingThread(void *para)
#else
void* ThreadService::WorkingThread(void *para)
#endif
{
	ThreadService* pthis = (ThreadService*)para;
	{
		miniutil::auto_lock kk(&pthis->mservice_mtx);
		//Start must have finished
	}

    pthis->InnerRunException();

	if(pthis->exitflg == 1)//when stop by STOP, not lock
	{
		pthis->exitflg = 2;
	}
	else
	{
		pthis->mservice_mtx.lock();
		pthis->mbrunning = false;
#ifdef WIN32
		pthis->workerhandle = NULL;
#endif
		pthis->mservice_mtx.unlock();
	}
	pthis->mstoptm = time(NULL);
#ifdef WIN32
	return 0;
#else
	return NULL;
#endif
}


} }
